<template><div><h2 id="总结前端中导致url变化的场景有哪些" tabindex="-1"><a class="header-anchor" href="#总结前端中导致url变化的场景有哪些"><span>总结前端中导致url变化的场景有哪些</span></a></h2>
<ul>
<li>
<p>a标签跳转</p>
</li>
<li>
<p>修改window.location</p>
</li>
<li>
<p>浏览器的前进后退</p>
</li>
</ul>
<h2 id="vue-hash和history的分别是怎么实现的" tabindex="-1"><a class="header-anchor" href="#vue-hash和history的分别是怎么实现的"><span>vue hash和history的分别是怎么实现的</span></a></h2>
<p>前端路由主要从两个问题考虑，1.改变url不会发请求2.怎么检测url发生了变化</p>
<p>vue router 的hash模式基于window.location的hash值修改不会重新请求页面，监听hashChange事件，在进行DOM的修改</p>
<p>vue router的history模式基于window.history，history 提供了 pushState 和 replaceState 两个方法，<strong>这两个方法改变 URL 的 path 部分不会引起页面刷新</strong>，同时history 的back，go，forward方法会触发popState事件，监听popState事件并且拦截pushState和replaceState的调用以及a标签的点击事件，即可检测url的变化,进行DOM的修改</p>
<h2 id="hash模式如何更新url" tabindex="-1"><a class="header-anchor" href="#hash模式如何更新url"><span>hash模式如何更新url</span></a></h2>
<p>使用winodw.location即可</p>
<h2 id="hash路由和id锚点冲突要如何解决" tabindex="-1"><a class="header-anchor" href="#hash路由和id锚点冲突要如何解决"><span>hash路由和id锚点冲突要如何解决？</span></a></h2>
<p>法一：手动获取元素，使用scrollIntoView方法</p>
<div class="language-javascript line-numbers-mode" data-highlighter="shiki" data-ext="javascript" style="background-color:#282c34;color:#abb2bf"><pre class="shiki one-dark-pro vp-code" v-pre=""><code><span class="line"><span style="color:#C678DD">    const</span><span style="color:#E5C07B"> a</span><span style="color:#56B6C2"> =</span><span style="color:#E5C07B"> document</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">getElementById</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">"锚点id"</span><span style="color:#ABB2BF">);</span></span>
<span class="line"><span style="color:#7F848E;font-style:italic">    // scrollIntoView()将目标元素移动到浏览器顶部</span></span>
<span class="line"><span style="color:#7F848E;font-style:italic">    // scrollIntoView(false)将目标元素移动到浏览器底部</span></span>
<span class="line"><span style="color:#E5C07B">    a</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">scrollIntoView</span><span style="color:#ABB2BF">(); </span><span style="color:#7F848E;font-style:italic">// 通过scrollIntoView的方法来避免使用锚点</span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>法二：使用路由守卫,拦截所有非法路由</p>
<div class="language-javascript line-numbers-mode" data-highlighter="shiki" data-ext="javascript" style="background-color:#282c34;color:#abb2bf"><pre class="shiki one-dark-pro vp-code" v-pre=""><code><span class="line"><span style="color:#E5C07B">router</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">beforeEach</span><span style="color:#ABB2BF">((</span><span style="color:#E06C75;font-style:italic">to</span><span style="color:#ABB2BF">, </span><span style="color:#E06C75;font-style:italic">from</span><span style="color:#ABB2BF">) </span><span style="color:#C678DD">=></span><span style="color:#ABB2BF"> {</span></span>
<span class="line"><span style="color:#C678DD">	for</span><span style="color:#ABB2BF"> (</span><span style="color:#C678DD">var</span><span style="color:#E06C75"> rule</span><span style="color:#C678DD"> of</span><span style="color:#E06C75"> routes</span><span style="color:#ABB2BF">) </span></span>
<span class="line"><span style="color:#C678DD">		if</span><span style="color:#ABB2BF"> (</span><span style="color:#E5C07B">rule</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">path</span><span style="color:#56B6C2"> ==</span><span style="color:#E5C07B"> to</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">path</span><span style="color:#ABB2BF">)</span></span>
<span class="line"><span style="color:#C678DD">			return</span><span style="color:#ABB2BF">; </span></span>
<span class="line"><span style="color:#61AFEF">	alert</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">"导向404"</span><span style="color:#ABB2BF">);</span></span>
<span class="line"><span style="color:#C678DD">	return</span><span style="color:#ABB2BF"> { </span><span style="color:#E06C75">path</span><span style="color:#ABB2BF">: </span><span style="color:#98C379">'/404'</span><span style="color:#ABB2BF">};</span></span>
<span class="line"><span style="color:#ABB2BF">});</span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h2 id="练习" tabindex="-1"><a class="header-anchor" href="#练习"><span>练习</span></a></h2>
<p>弄一个有三个页面的vue应用程序，在主页面上放置一个后退按钮，用于调用路由实现后退功能；
编写vue的路由守卫，要求在history模式与hash模式下的都不允许连续后退三步以上</p>
<div class="language-javascript line-numbers-mode has-collapsed-lines collapsed" data-highlighter="shiki" data-ext="javascript" style="--vp-collapsed-lines:15;background-color:#282c34;color:#abb2bf"><pre class="shiki one-dark-pro vp-code" v-pre=""><code><span class="line"><span style="color:#C678DD">import</span><span style="color:#ABB2BF"> {</span></span>
<span class="line"><span style="color:#E06C75">	createWebHistory</span><span style="color:#ABB2BF">,</span></span>
<span class="line"><span style="color:#E06C75">	createWebHashHistory</span><span style="color:#ABB2BF">,</span></span>
<span class="line"><span style="color:#E06C75">	createRouter</span></span>
<span class="line"><span style="color:#ABB2BF">} </span><span style="color:#C678DD">from</span><span style="color:#98C379"> 'vue-router'</span></span>
<span class="line"></span>
<span class="line"><span style="color:#C678DD">const</span><span style="color:#E5C07B"> routes</span><span style="color:#56B6C2"> =</span><span style="color:#ABB2BF"> [</span></span>
<span class="line"><span style="color:#ABB2BF">	{</span></span>
<span class="line"><span style="color:#E06C75">		path</span><span style="color:#ABB2BF">: </span><span style="color:#98C379">'/1'</span><span style="color:#ABB2BF">,</span></span>
<span class="line"><span style="color:#61AFEF">		component</span><span style="color:#ABB2BF">: () </span><span style="color:#C678DD">=></span><span style="color:#61AFEF"> import</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">'../view/ViewOne.vue'</span><span style="color:#ABB2BF">) </span><span style="color:#7F848E;font-style:italic">// 懒加载</span></span>
<span class="line"><span style="color:#ABB2BF">	},</span></span>
<span class="line"><span style="color:#ABB2BF">	{</span></span>
<span class="line"><span style="color:#E06C75">		path</span><span style="color:#ABB2BF">: </span><span style="color:#98C379">'/2'</span><span style="color:#ABB2BF">,</span></span>
<span class="line"><span style="color:#61AFEF">		component</span><span style="color:#ABB2BF">: () </span><span style="color:#C678DD">=></span><span style="color:#61AFEF"> import</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">'../view/ViewTwo.vue'</span><span style="color:#ABB2BF">)</span></span>
<span class="line"><span style="color:#ABB2BF">	},</span></span>
<span class="line"><span style="color:#ABB2BF">	{</span></span>
<span class="line"><span style="color:#E06C75">		path</span><span style="color:#ABB2BF">: </span><span style="color:#98C379">'/3'</span><span style="color:#ABB2BF">,</span></span>
<span class="line"><span style="color:#61AFEF">		component</span><span style="color:#ABB2BF">: () </span><span style="color:#C678DD">=></span><span style="color:#61AFEF"> import</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">'../view/ViewThree.vue'</span><span style="color:#ABB2BF">)</span></span>
<span class="line"><span style="color:#ABB2BF">	},</span></span>
<span class="line"><span style="color:#ABB2BF">	{</span></span>
<span class="line"><span style="color:#E06C75">		path</span><span style="color:#ABB2BF">:</span><span style="color:#98C379">'/404'</span><span style="color:#ABB2BF">,</span></span>
<span class="line"><span style="color:#ABB2BF">		</span></span>
<span class="line"><span style="color:#ABB2BF">	}</span></span>
<span class="line"><span style="color:#ABB2BF">];</span></span>
<span class="line"></span>
<span class="line"><span style="color:#C678DD">const</span><span style="color:#E5C07B"> router</span><span style="color:#56B6C2"> =</span><span style="color:#61AFEF"> createRouter</span><span style="color:#ABB2BF">({</span></span>
<span class="line"><span style="color:#E06C75">	history</span><span style="color:#ABB2BF">: </span><span style="color:#61AFEF">createWebHistory</span><span style="color:#ABB2BF">(), </span><span style="color:#7F848E;font-style:italic">// history模式</span></span>
<span class="line"><span style="color:#7F848E;font-style:italic">	// history: createWebHashHistory(),</span><span style="color:#7F848E;font-style:italic"> // hash模式</span></span>
<span class="line"><span style="color:#E06C75">	routes</span></span>
<span class="line"><span style="color:#ABB2BF">});</span></span>
<span class="line"></span>
<span class="line"><span style="color:#C678DD">const</span><span style="color:#E5C07B"> originalBack</span><span style="color:#56B6C2"> =</span><span style="color:#E5C07B"> router</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">back</span><span style="color:#ABB2BF">;</span></span>
<span class="line"><span style="color:#E5C07B">router</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">back</span><span style="color:#56B6C2"> =</span><span style="color:#ABB2BF"> () </span><span style="color:#C678DD">=></span><span style="color:#ABB2BF"> { </span><span style="color:#7F848E;font-style:italic">// 重写back方法</span></span>
<span class="line"><span style="color:#E5C07B">	router</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">isBack</span><span style="color:#56B6C2"> =</span><span style="color:#D19A66"> true</span><span style="color:#ABB2BF">;</span></span>
<span class="line"><span style="color:#61AFEF">	originalBack</span><span style="color:#ABB2BF">();</span></span>
<span class="line"><span style="color:#ABB2BF">}</span></span>
<span class="line"><span style="color:#C678DD">let</span><span style="color:#E06C75"> backCount</span><span style="color:#56B6C2"> =</span><span style="color:#D19A66"> 0</span><span style="color:#ABB2BF">;</span></span>
<span class="line"><span style="color:#E5C07B">router</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">beforeEach</span><span style="color:#ABB2BF">((</span><span style="color:#E06C75;font-style:italic">to</span><span style="color:#ABB2BF">, </span><span style="color:#E06C75;font-style:italic">from</span><span style="color:#ABB2BF">) </span><span style="color:#C678DD">=></span><span style="color:#ABB2BF"> {</span></span>
<span class="line"><span style="color:#C678DD">	if</span><span style="color:#ABB2BF"> (</span><span style="color:#E5C07B">router</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">isBack</span><span style="color:#ABB2BF">) {</span></span>
<span class="line"><span style="color:#E06C75">		backCount</span><span style="color:#56B6C2">++</span><span style="color:#ABB2BF">;</span></span>
<span class="line"><span style="color:#E5C07B">		router</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">isBack</span><span style="color:#56B6C2"> =</span><span style="color:#D19A66"> false</span><span style="color:#ABB2BF">;</span></span>
<span class="line"><span style="color:#C678DD">		if</span><span style="color:#ABB2BF"> (</span><span style="color:#E06C75">backCount</span><span style="color:#56B6C2"> ></span><span style="color:#D19A66"> 2</span><span style="color:#ABB2BF">) {</span></span>
<span class="line"><span style="color:#E06C75">			backCount</span><span style="color:#56B6C2"> =</span><span style="color:#D19A66"> 0</span><span style="color:#ABB2BF">;</span></span>
<span class="line"><span style="color:#61AFEF">			alert</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">'不允许连续后退三步'</span><span style="color:#ABB2BF">);</span></span>
<span class="line"><span style="color:#C678DD">			return</span><span style="color:#E06C75"> from</span><span style="color:#ABB2BF">; </span><span style="color:#7F848E;font-style:italic">// 返回页面</span></span>
<span class="line"><span style="color:#ABB2BF">		}</span></span>
<span class="line"><span style="color:#ABB2BF">	} </span><span style="color:#C678DD">else</span><span style="color:#ABB2BF"> {</span></span>
<span class="line"><span style="color:#E06C75">		backCount</span><span style="color:#56B6C2"> =</span><span style="color:#D19A66"> 0</span><span style="color:#ABB2BF">;</span></span>
<span class="line"><span style="color:#C678DD">		return</span><span style="color:#ABB2BF"> ;</span></span>
<span class="line"><span style="color:#ABB2BF">	}</span></span>
<span class="line"><span style="color:#ABB2BF">})</span></span>
<span class="line"></span>
<span class="line"></span>
<span class="line"><span style="color:#C678DD">export</span><span style="color:#C678DD"> default</span><span style="color:#E06C75"> router</span><span style="color:#ABB2BF">;</span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div><div class="collapsed-lines"></div></div><blockquote>
<p>参考：<br>
<a href="https://cloud.tencent.com/developer/article/1880448" target="_blank" rel="noopener noreferrer">手写Vue-router核心原理，再也不怕面试官问我Vue-router原理-腾讯云开发者社区-腾讯云</a></p>
<p><a href="https://juejin.cn/post/7146408382251925540" target="_blank" rel="noopener noreferrer">vue router 4 源码篇：router history的原生结合vue-router是vue官方指定的路由管理库 - 掘金</a></p>
</blockquote>
</div></template>


